package com.backend.modules.system.service.impl;

import com.backend.common.enums.DeptType;
import com.backend.common.enums.UserType;
import com.backend.common.exception.BusinessException;
import com.backend.common.utils.ExcelUtils;
import com.backend.common.utils.SecurityUtils;
import com.backend.modules.system.dto.ClassStudentQueryDTO;
import com.backend.modules.system.dto.StudentDTO;
import com.backend.modules.system.dto.StudentExcelDTO;
import com.backend.modules.system.entity.SysDepartment;
import com.backend.modules.system.entity.SysUser;
import com.backend.modules.system.repository.SysTeacherClassRepository;
import com.backend.modules.system.repository.SysUserRepository;
import com.backend.modules.system.service.SysDepartmentService;
import com.backend.modules.system.service.TeacherClassService;
import com.backend.modules.system.vo.ClassTreeVO;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.Predicate;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class TeacherClassServiceImpl implements TeacherClassService {

    private final SysTeacherClassRepository teacherClassRepository;
    private final SysUserRepository userRepository;
    private final SysDepartmentService departmentService;
    private final PasswordEncoder passwordEncoder;

    @Override
    public List<ClassTreeVO> getTeacherClassTree() {
        // 获取教师负责的班级ID列表
        List<Long> classIds = teacherClassRepository.findClassIdsByTeacherId(
                SecurityUtils.getCurrentUserId());
        
        if (classIds.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 获取班级信息
        List<SysDepartment> classes = classIds.stream()
                .map(departmentService::getById)
                .collect(Collectors.toList());
        
        // 构建班级树
        Map<Long, ClassTreeVO> treeMap = new HashMap<>();
        
        // 处理所有部门节点
        for (SysDepartment dept : classes) {
            buildTreeNode(dept, treeMap);
        }
        
        // 返回根节点
        return treeMap.values().stream()
                .filter(node -> node.getParentId() == null)
                .collect(Collectors.toList());
    }

    @Override
    public Page<SysUser> getClassStudents(Long classId, ClassStudentQueryDTO query, Pageable pageable) {
        // 验证班级是否存在且是否有权限
        SysDepartment classDept = departmentService.getById(classId);
        if (!DeptType.CLASS.getValue().equals(classDept.getType())) {
            throw new BusinessException("不是有效的班级");
        }
        
        // 验证教师是否有权限访问该班级
        List<Long> teacherClassIds = teacherClassRepository.findClassIdsByTeacherId(
                SecurityUtils.getCurrentUserId());
        if (!teacherClassIds.contains(classId)) {
            throw new BusinessException("无权访问该班级");
        }
        
        // 构建查询条件
        Specification<SysUser> spec = (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            // 只查询学生
            predicates.add(criteriaBuilder.equal(root.get("userType"), 
                    UserType.STUDENT.getValue()));
            
            // 班级过滤
            predicates.add(criteriaBuilder.equal(root.get("department").get("id"), classId));
            
            // 学号
            if (StringUtils.hasText(query.getUserCode())) {
                predicates.add(criteriaBuilder.like(root.get("userCode"), 
                        "%" + query.getUserCode() + "%"));
            }
            
            // 姓名
            if (StringUtils.hasText(query.getRealName())) {
                predicates.add(criteriaBuilder.like(root.get("realName"), 
                        "%" + query.getRealName() + "%"));
            }
            
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };
        
        return userRepository.findAll(spec, pageable);
    }
    
    /**
     * 构建树节点
     */
    private void buildTreeNode(SysDepartment dept, Map<Long, ClassTreeVO> treeMap) {
        // 如果节点已存在，直接返回
        if (treeMap.containsKey(dept.getId())) {
            return;
        }
        
        // 创建当前节点
        ClassTreeVO node = new ClassTreeVO();
        node.setId(dept.getId());
        node.setName(dept.getName());
        node.setType(dept.getType());
        node.setParentId(dept.getParent() != null ? dept.getParent().getId() : null);
        
        // 处理父节点
        if (dept.getParent() != null) {
            buildTreeNode(dept.getParent(), treeMap);
            ClassTreeVO parentNode = treeMap.get(dept.getParent().getId());
            parentNode.getChildren().add(node);
            
            // 设置完整路径
            node.setFullPath(parentNode.getFullPath() + "/" + dept.getName());
        } else {
            node.setFullPath(dept.getName());
        }
        
        // 将节点加入Map
        treeMap.put(dept.getId(), node);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createStudent(Long classId, StudentDTO dto) {
        // 验证班级是否存在且教师是否有权限
        validateTeacherClass(classId);
        
        // 校验学号是否存在
        if (userRepository.existsByUserCode(dto.getUserCode())) {
            throw new BusinessException("学号已存在");
        }

        // 创建学生
        SysUser student = new SysUser();
        String userCode = dto.getUserCode();
        student.setUserCode(userCode);
        student.setUsername(userCode); // 用学号作为用户名
        student.setPassword(passwordEncoder.encode(userCode)); // 默认密码为学号
        student.setRealName(dto.getRealName());
        student.setPhone(dto.getPhone());
        student.setEmail(dto.getEmail());
        student.setUserType(UserType.STUDENT.getValue());
        student.setStatus(true);
        student.setDepartment(departmentService.getById(classId));
        student.setGender(dto.getGender());

        userRepository.save(student);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStudent(Long classId, Long studentId, StudentDTO dto) {
        // 验证班级是否存在且教师是否有权限
        validateTeacherClass(classId);
        
        // 获取并验证学生
        SysUser student = validateStudent(classId, studentId);
        
        // 如果修改了学号，需要验证新学号是否存在
        if (!student.getUserCode().equals(dto.getUserCode()) 
                && userRepository.existsByUserCode(dto.getUserCode())) {
            throw new BusinessException("学号已存在");
        }

        // 更新学生信息
        String userCode = dto.getUserCode();
        student.setUserCode(userCode);
        student.setUsername(userCode); // 同步更新用户名
        student.setRealName(dto.getRealName());
        student.setPhone(dto.getPhone());
        student.setEmail(dto.getEmail());
        student.setGender(dto.getGender());

        userRepository.save(student);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteStudent(Long classId, Long studentId) {
        // 验证班级是否存在且教师是否有权限
        validateTeacherClass(classId);
        
        // 获取并验证学生
        SysUser student = validateStudent(classId, studentId);
        
        // 删除学生
        userRepository.delete(student);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetStudentPassword(Long classId, Long studentId) {
        // 验证班级是否存在且教师是否有权限
        validateTeacherClass(classId);
        
        // 获取并验证学生
        SysUser student = validateStudent(classId, studentId);
        
        // 重置密码为学号
        student.setPassword(passwordEncoder.encode(student.getUserCode()));
        userRepository.save(student);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStudentStatus(Long classId, Long studentId, Boolean status) {
        // 验证班级是否存在且教师是否有权限
        validateTeacherClass(classId);
        
        // 获取并验证学生
        SysUser student = validateStudent(classId, studentId);
        
        // 更新状态
        student.setStatus(status);
        userRepository.save(student);
    }

    /**
     * 验证教师是否有权限管理该班级
     */
    private void validateTeacherClass(Long classId) {
        List<Long> classIds = teacherClassRepository.findClassIdsByTeacherId(
                SecurityUtils.getCurrentUserId());
        if (!classIds.contains(classId)) {
            throw new BusinessException("无权操作该班级");
        }
    }

    /**
     * 验证学生是否存在且属于指定班级
     */
    private SysUser validateStudent(Long classId, Long studentId) {
        SysUser student = userRepository.findById(studentId)
                .orElseThrow(() -> new BusinessException("学生不存在"));
        
        if (!UserType.STUDENT.getValue().equals(student.getUserType())) {
            throw new BusinessException("用户不是学生");
        }
        
        if (student.getDepartment() == null || !student.getDepartment().getId().equals(classId)) {
            throw new BusinessException("学生不属于该班级");
        }
        
        return student;
    }

    @Override
    public ResponseEntity<byte[]> exportStudents(Long classId) {
        // 验证班级是否存在且教师是否有权限
        validateTeacherClass(classId);
        
        // 获取班级信息
        SysDepartment classDept = departmentService.getById(classId);
        
        // 获取班级学生列表
        List<SysUser> students = userRepository.findByDepartmentIdAndUserType(
                classId, UserType.STUDENT.getValue());
        
        // 转换为Excel DTO
        List<StudentExcelDTO> excelData = students.stream().map(student -> {
            StudentExcelDTO dto = new StudentExcelDTO();
            dto.setUserCode(student.getUserCode());
            dto.setRealName(student.getRealName());
            dto.setPhone(student.getPhone());
            dto.setEmail(student.getEmail());
            dto.setGender(student.getGender());
            return dto;
        }).collect(Collectors.toList());
        
        // 导出Excel
        return ExcelUtils.export(excelData, 
                classDept.getName() + "学生名单", 
                "学生列表", 
                StudentExcelDTO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ExcelUtils.ImportResult<StudentExcelDTO> importStudents(Long classId, MultipartFile file) {
        // 验证班级是否存在且教师是否有权限
        validateTeacherClass(classId);
        SysDepartment classDept = departmentService.getById(classId);
        
        // 导入Excel
        return ExcelUtils.importExcel(file, StudentExcelDTO.class, dto -> {
            // 验证必填字段
            if (!StringUtils.hasText(dto.getUserCode())) {
                throw new IllegalArgumentException("学号不能为空");
            }
            if (!StringUtils.hasText(dto.getRealName())) {
                throw new IllegalArgumentException("姓名不能为空");
            }
            if (dto.getGender() == null) {
                throw new IllegalArgumentException("性别不能为空");
            }
            
            // 验证学号是否已存在
            if (userRepository.existsByUserCode(dto.getUserCode())) {
                throw new IllegalArgumentException("学号已存在：" + dto.getUserCode());
            }
            
            // 创建学生
            SysUser student = new SysUser();
            student.setUserCode(dto.getUserCode());
            student.setUsername(dto.getUserCode()); // 用学号作为用户名
            student.setPassword(passwordEncoder.encode(dto.getUserCode())); // 默认密码为学号
            student.setRealName(dto.getRealName());
            student.setPhone(dto.getPhone());
            student.setEmail(dto.getEmail());
            student.setGender(dto.getGender());
            student.setUserType(UserType.STUDENT.getValue());
            student.setStatus(true);
            student.setDepartment(classDept);
            
            userRepository.save(student);
        });
    }

    @Override
    public ResponseEntity<byte[]> downloadStudentTemplate() {
        return ExcelUtils.generateTemplate(
                "学生导入模板",
                "学生信息",
                StudentExcelDTO.class);
    }
} 